package cn.tedu.csmall.passport.service.impl;

import cn.tedu.csmall.commons.ex.ServiceException;
import cn.tedu.csmall.commons.util.PageInfoToPageDataConverter;
import cn.tedu.csmall.commons.vo.PageData;
import cn.tedu.csmall.commons.web.ServiceCode;
import cn.tedu.csmall.passport.mapper.AdminMapper;
import cn.tedu.csmall.passport.mapper.AdminRoleMapper;
import cn.tedu.csmall.passport.pojo.entity.Admin;
import cn.tedu.csmall.passport.pojo.entity.AdminRole;
import cn.tedu.csmall.passport.pojo.param.AdminAddNewParam;
import cn.tedu.csmall.passport.pojo.param.AdminLoginInfoParam;
import cn.tedu.csmall.passport.pojo.param.AdminUpdateParam;
import cn.tedu.csmall.passport.pojo.vo.AdminListItemVO;
import cn.tedu.csmall.passport.pojo.vo.AdminStandardVO;
import cn.tedu.csmall.passport.security.AdminDetais;
import cn.tedu.csmall.passport.service.IAdminService;
import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Service;

import java.time.LocalDateTime;
import java.util.*;

/**
 * @author Administrator
 * @description 针对表【ams_admin(管理员)】的数据库操作Service实现
 * @createDate 2023-06-16 11:20:58
 */
@Service
@Slf4j
public class AdminServiceImpl implements IAdminService {

    @Value("${csmall.jwt.secret-key}")
    private String secretKey;

    @Value("${csmall.jwt.duration-in-minute}")
    private Long durationInMinute;


    @Autowired
    private AdminMapper adminMapper;

    @Autowired
    private AdminRoleMapper adminRoleMapper;

    @Autowired
    private PasswordEncoder passwordEncoder;

    @Autowired
    private AuthenticationManager authenticationManager;


    @Override
    public void addNew(AdminAddNewParam adminAddNewParam) {
        log.debug("开始处理[添加管理员]的业务，参数:{}", adminAddNewParam);


        QueryWrapper<Admin> queryWrapper = new QueryWrapper<>();

        //                      字段值
        queryWrapper.eq("username", adminAddNewParam.getUsername());
        int countByName = adminMapper.selectCount(queryWrapper);
        log.debug("根据管理员名称统计匹配的管理员数量，结果:{}", countByName);
        //如果管理员存在大于0
        if (countByName > 0) {
            String message = "添加管理员失败，管理员名称已经被占用";
            log.warn(message);
            throw new ServiceException(ServiceCode.ERR_CONFLICT, message);
        }

        //TODO 检查管理员手机号码是否被占用，如果被占用，则抛出异常
        //TODO 检查管理员电子邮箱是否被占用，如果被占用，则抛出异常

        Admin admin = new Admin();
        BeanUtils.copyProperties(adminAddNewParam, admin);
        admin.setLastLoginIp(null);
        admin.setLoginCount(0);
        admin.setGmtLastLogin(LocalDateTime.now());
        admin.setGmtCreate(LocalDateTime.now());
        admin.setGmtModified(LocalDateTime.now());
        log.debug("准备将新的管理员数据写入到数据库,数据：{}", admin);
        int rows = adminMapper.insert(admin);
        if (rows != 1) {
            String message = "添加管理员失败！服务器忙，请稍后再试！";
            log.warn(message);
            throw new ServiceException(ServiceCode.ERR_INSERT, message);
        }

        log.debug("将新的管理员数据写入到数据库，完成！");

        //将管理员与角色的关联数据写入到数据库中
        Long[] roleIds = adminAddNewParam.getRoleIds();
        AdminRole[] adminRoleList = new AdminRole[roleIds.length];
        LocalDateTime now = LocalDateTime.now();
        for (int i = 0; i < adminRoleList.length; i++) {
            AdminRole adminRole = new AdminRole();
            adminRole.setAdminId(admin.getId());
            adminRole.setRoleId(roleIds[i]);
            adminRole.setGmtCreate(now);
            adminRole.setGmtModified(now);
            adminRoleList[i] = adminRole;

        }

        rows = adminRoleMapper.insertBatch(adminRoleList);
        if (rows != adminRoleList.length) {
            String message = "添加管理员失败！服务器忙，请稍后再试！";
            log.warn(message);
            throw new ServiceException(ServiceCode.ERR_INSERT, message);
        }
        log.debug("将新的管理员与角色的关联数据插入到数据库，完成！");


    }


    @Override
    public String login(AdminLoginInfoParam adminLoginInfoParam) {
        log.debug("开始处理[管理员登录]的业务，参数:{}", adminLoginInfoParam);
        //创建认证时所需的参数对象
        Authentication authentication = new UsernamePasswordAuthenticationToken(
                adminLoginInfoParam.getUsername(),
                adminLoginInfoParam.getPassword()
        );
        Authentication authenticateResult
                = authenticationManager.authenticate(authentication);
        log.debug("验证登录完成，认证结果：{}", authenticateResult);

        //从认证结果中取出所需的数据
        Object principal = authenticateResult.getPrincipal();
        AdminDetais adminDetais = (AdminDetais) principal;
        Collection<GrantedAuthority> authorities = adminDetais.getAuthorities();




        Map<String, Object> claims = new HashMap<>();
        claims.put("id", adminDetais.getId());
        claims.put("username", adminDetais.getUsername());
        claims.put("authoritiesJSONString", JSON.toJSONString(authorities));

        String jwt = Jwts.builder()
                //Header
                .setHeaderParam("alg", "HS256")
                .setHeaderParam("typ", "JWT")


                //Payload
                .setClaims(claims)
                .setExpiration(new Date(System.currentTimeMillis() +durationInMinute*1000*60))


                //Verify Signature
                .signWith(SignatureAlgorithm.HS256, secretKey)

                //生成
                .compact();
        log.debug("生成了此管理员的信息对应的JWT:{}", jwt);
        return jwt;

        //将认证结果存入到SecurityContext中
        //解决登录后没有权限报403错误
        //========使用JWT后不再需要以下2行代码
        //SecurityContext securityContext = SecurityContextHolder.getContext();
        //securityContext.setAuthentication(authenticateResult);

    }

    @Override
    public void deleteById(Long id) {
        log.info("开始:【删除用户】");
        log.debug("传入参数,id={}", id);
        //检查用户ID检查用户是否存在数据，如果不存在，则抛出异常
        QueryWrapper<Admin> queryWrapper2 = new QueryWrapper<>();
        queryWrapper2.eq("id", id);
        int countById = adminMapper.selectCount(queryWrapper2);
        log.info("规则：根据用户id检索数据库结果,countById={}", countById);
        if(countById == 0){
            log.info("结果2:根据用户id检索数据量为0，抛出异常...");
            throw new ServiceException(ServiceCode.ERR_NOT_FOUND, "删除用户失败，用户数据不存在！");
        }

        log.info("删除用户数据...");
        int rows = adminMapper.deleteById(id);
        if(rows != 1){
            String message = "删除用户失败，服务器忙，请稍后再试！";
            log.info("结果1:数据返回行数不满足预估行数，预估={}, 实际={}, 抛出自定异常...", 1, rows);
            throw new ServiceException(ServiceCode.ERR_DELETE, message);
        }
        log.info("结果1:删除用户结果,rows={}", rows);

        log.info("删除用户角色关系数据...");
        int rows2 = adminRoleMapper.deleteByAdminId(id);
        log.info("结果1:删除用户角色关系结果,rows2={}", rows2);
    }



    @Override
    public void updateInfoById(Long id, AdminUpdateParam adminUpdateParam) {
        log.info("开始:【更新用户信息】");
        log.debug("传入参数,id={}", id);
        //检查用户ID检查用户是否存在数据，如果不存在，则抛出异常
        QueryWrapper<Admin> queryWrapper2 = new QueryWrapper<>();
        queryWrapper2.eq("id", id);
        int countById = adminMapper.selectCount(queryWrapper2);
        log.info("规则：根据用户id检索数据库结果,countById={}", countById);
        if(countById == 0){
            log.info("结果2:根据用户id检索数据量为0，抛出异常...");
            throw new ServiceException(ServiceCode.ERR_NOT_FOUND, "更新用户失败，用户数据不存在！");
        }

        //检查手机号称是否被其他账号占用，如果被占用，则抛出异常
        QueryWrapper<Admin> queryWrapper3 = new QueryWrapper<>();
        queryWrapper3.eq("phone",adminUpdateParam.getPhone())
                .ne("id", id);
        int countByPhone = adminMapper.selectCount(queryWrapper3);
        log.info("规则：根据手机号称检索数据库结果,countByPhone={}", countByPhone);
        if(countByPhone > 0){
            log.info("结果3:不满足用户更新规则【手机号不可重复】，抛出自定异常...");
            throw new ServiceException(ServiceCode.ERR_CONFLICT, "更新用户失败，手机号已存在！");
        }

        //检查邮箱称是否被占用，如果被占用，则抛出异常
        QueryWrapper<Admin> queryWrapper4 = new QueryWrapper<>();
        queryWrapper4.eq("email",adminUpdateParam.getEmail())
                .ne("id", id);;
        int countByEmail = adminMapper.selectCount(queryWrapper4);
        log.info("规则：根据邮箱检索数据库结果,countByEmail={}", countByEmail);
        if(countByEmail > 0){
            log.info("结果4:不满足用户更新规则【邮箱不可重复】，抛出自定异常...");
            throw new ServiceException(ServiceCode.ERR_CONFLICT, "更新用户失败，邮箱已存在！");
        }

        Admin admin = new Admin();
        BeanUtils.copyProperties(adminUpdateParam, admin);
        admin.setId(id);
        int rows = adminMapper.updateById(admin);
        if(rows != 1){
            String message = "编辑用户失败，服务器忙，请稍后再试！";
            log.info("结果1:数据返回行数不满足预估行数，预估={}, 实际={}, 抛出自定异常...", 1, rows);
            throw new ServiceException(ServiceCode.ERR_UPDATE, message);
        }
        log.info("结果1:根据id编辑用户结果,rows={}", rows);
    }

    @Override
    public void updatePwdById(Long id, String password) {
        log.info("开始:【更新密码】");
        log.debug("传入参数,id={}", id);

        //检查用户ID检查用户是否存在数据，如果不存在，则抛出异常
        QueryWrapper<Admin> queryWrapper2 = new QueryWrapper<>();
        queryWrapper2.eq("id", id);
        int countById = adminMapper.selectCount(queryWrapper2);
        log.info("规则：根据用户id检索数据库结果,countById={}", countById);
        if(countById == 0){
            log.info("结果2:根据用户id检索数据量为0，抛出异常...");
            throw new ServiceException(ServiceCode.ERR_NOT_FOUND, "删除用户失败，用户数据不存在！");
        }

        Admin admin = new Admin();
        admin.setId(id);
        String encodePwd = passwordEncoder.encode(password);
        admin.setPassword(encodePwd);
        log.debug("更新密码数据,admin={}", admin);
        int rows = adminMapper.updateById(admin);
        if(rows != 1){
            String message = "更新密码失败，服务器忙，请稍后再试！";
            log.info("结果1:数据返回行数不满足预估行数，预估={}, 实际={}, 抛出自定异常...", 1, rows);
            throw new ServiceException(ServiceCode.ERR_UPDATE, message);
        }
        log.info("结果1:根据id编辑密码结果,rows={}", rows);

    }

    @Override
    public AdminStandardVO getStandardById(Long id) {
        log.info("开始:【根据ID查询用户】");
        log.debug("传入参数,id={}", id);
        AdminStandardVO standardById = adminMapper.getStandardById(id);

        //根据用户ID检查用户是否存在数据，如果不存在，则抛出异常
        if(standardById==null){
            log.info("结果2:根据id查询详情，结果为null，抛出异常...");
            throw new ServiceException(ServiceCode.ERR_NOT_FOUND, "查询用户详情失败，用户数据不存在");
        }

        log.info("结果1:查询出数据,standardById");
        return standardById;
    }

    @Override
    public PageData<AdminListItemVO> list(Integer pageNum) {
        Integer pageSize = 5;
        return list(pageNum, pageSize);
    }

    @Override
    public PageData<AdminListItemVO> list(Integer pageNum, Integer pageSize) {
        log.info("开始:【查询-用户-分页】");
        log.debug("传入参数, pageNum={}, pageSize={}", pageNum, pageSize);
        PageHelper.startPage(pageNum, pageSize);
        List<AdminListItemVO> list = adminMapper.list();
        PageInfo<AdminListItemVO> pageInfo = new PageInfo<>(list);
        PageData<AdminListItemVO> pageData = PageInfoToPageDataConverter.convert(pageInfo);
        log.debug("结果1: 查询结果：pageData={}", pageData);
        return pageData;
    }
}




